Bake Smarter with Bake Mate | designnews.com

2022-08-27 23:41:52 By : Ms. Shirley Zhang

Design News is part of the Informa Markets Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.

See All Automotive Engineering »

See All Design Software »

This project was one of the winners of the Pi Chef Design Challenge sponsored by Element14.com.

CLICK HERE to download a fully detailed PDF of the Bake Mate build instructions with more graphics, photos, and full coding examples.

Here are a few reasons baking can be a hassle:

My solution to these problems is Bake Mate:

It consists of a Raspberry Pi 3, a 2.4" touchscreen PiTFT HAT, a load cell, and a thermocouple.

The Pi runs an application (built using Python & Tkinter) that displays the recipe. The load cell connected to the Pi weighs the mixing bowl and automatically detects how much of an ingredient has been added and notifies the user how much more is needed.

The recipes are formatted as JSON files that allow the application to parse data like the ingredients, instructions, baking time, etc.

The device also does automatic unit conversion. If the original recipe uses pounds or cups of flour, the application will automatically convert it to the desired unit (e.g., grams or ounces). Because the weighing scale is connected to the Pi, it will automatically detect the weight of the mixing bowl in an easy step and inform the user how much more of the ingredient needs to be added.

A typical ‘Bake Mate’ session would look something like:

1.) Setting up the Raspberry Pi 3:

2.) How to Code Recipe Files

I decided to store recipes on json files so that they’re easy to parse. I’ve detailed the format I used below.

Sample Python code for parsing json:

import glob import json def getFiles(): #get a list of files    fileList = glob.glob('*.json')    return fileList def getJSONname(s): #given the filename,    data = json.load(open(s)) #create a JSON object    print ("The recipe is",data["name"])    return (data["name"]) def getJSONservings(s): #given the filename,    data = json.load(open(s)) #create a JSON object    print ("Servings: ",data["Servings"])    return (data["Servings"]) def showJSON(data):    print (" ")    print ("The recipe is",data["name"])    print ("Something about it",data["Description"])    print ("Servings:",data["Servings"])    print ("Cooking time:",data["CookTime"])    nsteps = int(data["nSteps"])    print ("Number of steps:",nsteps)    print (" ")    for x in range (nsteps):        print("Step index" + str(x))        print ("Step ",data["Steps"][x]["num"])        print (data["Steps"][x]["ingr"])        print ("Instruction type",data["Steps"][x]["type"])        print ("Ingredient:",data["Steps"][x]["ingr"])        print ("Unit:",data["Steps"][x]["ingrUnit"])        print ("Value:",data["Steps"][x]["ingrValue"])        print ("BakeTime:",data["Steps"][x]["bakeTime"])        print ("BakeTemp:",data["Steps"][x]["bakeTemp"])        print ("BakeTempUnit:",data["Steps"][x]["bakeTempUnit"])        print (data["Steps"][x]["txt"],data["Steps"][x]["ingrValue"],data["Steps"][x]["ingrUnit"],"of",data["Steps"][x]["ingr"])        print (" ") fileList = getFiles() #get list of files for filename in fileList: #for each file...    print

("------------------------------------------------------")    print ("File is ",filename)    data = json.load(open(filename)) #createJSON object    showJSON(data)    getJSONname(filename) #get the recipe name

3.) Monitoring Temperature with the Type K Thermocouple + MAX31856:

Because the Display HAT uses hardware SPI, I decided to use a software (bit-banged) SPI to connect the MAX31856. Another issue is that the Display HAT doesn’t break out any of the unused pins, so I’ll be using a breakout board for now:

The MAX31856 board on the right: SPI, power, and GND lines on the top go to the Pi and the thermocouple is connected at the bottom. 

I used Stephen Smith's Python based MAX31856 library.

I placed the tip of the thermocouple on the Pi’s SoC and ran a test script to measure temperature.

4.) Testing the weighing scale: load cell + HX711

I built a test scale to test out the load-cell and HX711.

The load cell consists of strain gauges attached to the metal block. When a weight is applied, the block bends, which changes the resistance of the strain gauges. Monitoring the voltage with an ADC will allow you to measure resistance.

I used tatobari's HX711 Python Library, which contains instructions on how to calibrate the load cell and everything else you need to know.

For this quickly put together scale, I used some components I found lying around the house. I plan on designing and building a nicer one sometime soon.

The code for the application is based on Python 3 and uses Tkinter for the GUI.

Here’s a quick look at how I arranged everything in the GUI:

This one is the simplest of all, and just contains a splash screen.

This one isn't really needed at this point because I haven't started working on the part that lets the user create a recipe, which I hope to do soon. For now, the user presses on the button to "View Recipes."

This page displays a list of all the recipes in the folder, along with a short description of the selected recipe.

After selecting the recipe, the user gets an option to scale the quantity. The application will automatically handle the converted weights of every ingredient, which makes everything easier.

When this page is displayed, a Python module called "thisRecipe" gets initialized with a bunch of values that will be used to keep track of the recipe's ongoing progress. This module will be used as a global variable that can be accessed by all the classes (which contain data for each page of the GUI).

Now that the first few pages are done, we move on to the pages that will actually display each step of the recipe.

I've broken the steps down into the four more probable types: “add measurable ingredient,” “add non-measurable ingredient,” “do (basic instructions like mixing, etc.),” and “bake.” These should be sufficient for baking, and I could always add more types if I ever encounter a recipe that needs it.

Each page will have a unique GUI and backend. The page for "add measureable ingredient" will need to access the data from the weighing scale using the HX711 library, which I've already covered and tested. The page for "bake " will contain a timer and will need to access oven temperature using the MAX31856 library. Each of these pages will also need to parse the required data from the step in the JSON file: weight or temperature. Naturally, all four of these pages have been designed as templates so that they can be reused. At each step, the required data is parsed and displayed in the respective field.

To keep track of each step, I use global variables that are declared in another file (thisrecipe.py). Because the four 'step' pages might be required in any random order (since it depends entirely on the recipe), I decided to implement it in a manner that certain tasks are performed when the particular page is first called (the enter tasks) and when it is left (the exit tasks).

The first time a page is invoked, it'll look at the current instruction number (in thisrecipe.py) and parse the required data from that particular step (weight, text, etc.).

Once the task of the page is done, the user presses on the "Next" button, which executes the exit tasks. The exit tasks basically increment the value of cur_step, and parse the instruction type of the next (upcoming step) from the JSON file. If the next step is "addm," the next page that is called is of the "add measureable" type. If it is a "do," the next page will be a "do" type; and so on.

Have a look at the block diagram above. The order in which the pages are invoked depends entirely on the recipe. At the end of every step, the next page type is determined and automatically invoked. Throughout the process, thisRecipe.py is used to keep track of the current step. Another parameter that needs to be tracked is the weight detected on the weighing scale so that the weight at each step can be calculated.

6.) A Visual Indicator Using Sense HAT's RGB LED Matrix

I wanted to use the LED matrix on the Sense HAT as an indicator of how much of the ingredient has been added by making the matrix fill up as the required amount is added.

Using the Sense HAT on the Pi simultaneously with the Display HAT is complicated because HATs aren’t stackable, due to the identification EEPROM that is present on every HAT.

In order to get around this restriction, I used this code to control the matrix using I2C instead of using the library that comes with the Sense HAT.

I made use of IFTTT’s notification service to send alerts when the oven’s temperature deviates too far from the temperature required by the recipe, and when the baking timer elapses (with a couple of notifications at predefined intervals in the middle).

Here’s an example of invoking an IFTTT notification from Python:

import requests IFTTT_WEBHOOKS_URL = 'https://maker.ifttt.com/trigger/{}/with/key/' def post_ifttt_webhook(event, value):    data = {'value1': value} # The payload    ifttt_event_url = IFTTT_WEBHOOKS_URL.format(event) # Inserts event    requests.post(ifttt_event_url, json=data) # Sends a HTTP POST request to the webhook URL post_ifttt_webhook('BakeMateTimer',75)

[All images courtesy Avner Fernandes]

More information about text formats